package spring.boot.wx.mini.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.louislivi.fastdep.shirojwt.jwt.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import spring.boot.wx.mini.common.Results;
import spring.boot.wx.mini.common.Token;
import spring.boot.wx.mini.mapper.WxMiniUserMapper;
import spring.boot.wx.mini.model.WxMiniUser;
import spring.boot.wx.mini.utils.AesUtils;
import spring.boot.wx.mini.utils.Sha1Utils;
import spring.boot.wx.mini.vo.UserAuthVO;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

@Slf4j
@Service
public class WxMiniUserService extends ServiceImpl<WxMiniUserMapper, WxMiniUser> {


    @Value("${wx-mini.code-session-url}")
    private String codeSessionUrl;

    @Value("${wx-mini.app-id}")
    private String appId;

    @Value("${wx-mini.app-secret}")
    private String appSecret;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private JwtUtil jwtUtil;


    public Results login(String code) {
        log.info("code=[{}]", code);
        if (code == null || code.trim().length() <= 0) {
            log.error("参数 code 为空");
            return Results.paramError("参数 code 不能为空");
        }
        String url = codeSessionUrl.replace("APP_ID", appId).replace("APP_SECRET", appSecret).replace("JS_CODE", code);
        JSONObject codeSessionJson = null;
        try {
            codeSessionJson = restTemplate.getForObject(url, JSONObject.class);
            String openid = codeSessionJson.getString("openid");
            String sessionKey = codeSessionJson.getString("session_key");
            if (openid != null && openid.trim().length() > 0 && sessionKey != null && sessionKey.trim().length() > 0) {
                log.info("获取成功！ codeSessionJson=[{}]", codeSessionJson.toJSONString());
                WxMiniUser wxMiniUser = null;
                QueryWrapper<WxMiniUser> wrapper = new QueryWrapper<>();
                wrapper.eq("open_id", openid);
                List<WxMiniUser> wxMiniUsers = list(wrapper);
                if (wxMiniUsers != null && wxMiniUsers.size() > 0) {
                    wxMiniUser = wxMiniUsers.get(0);
                    wxMiniUser.setSessionKey(sessionKey);
                    updateById(wxMiniUser);
                } else {
                    wxMiniUser = new WxMiniUser();
                    wxMiniUser.setOpenId(openid);
                    wxMiniUser.setSessionKey(sessionKey);
                    wxMiniUser.setCreateTime(System.currentTimeMillis());
                    save(wxMiniUser);
                }
                return Results.success(jwtUtil.sign(String.valueOf(wxMiniUser.getId())));
            } else {
                Integer errCode = codeSessionJson.getInteger("errcode");
                String errMsg = codeSessionJson.getString("errmsg");
                log.error("获取openid 失败  errcode=[{}]  errmsg=[{}]", errCode, errMsg);
                return Results.error("err_code=[" + errCode + "],err_msg=[" + errMsg + "]");
            }
        } catch (Throwable e) {
            log.error("获取 codeSessionJson异常！appId=[{}] appSecret=[{}] code=[{}]", appId, appSecret, code);
            log.error(e.getMessage(), e);
            return Results.error("codeSessionJson异常");
        }
    }


    public Results auth(UserAuthVO userAuthVO, HttpServletRequest request) {
        if (userAuthVO == null) {
            log.error("参数 userAuthVO 为空");
            return Results.paramError("参数不能为空");
        }
        String rawData = userAuthVO.getRawData();
        if (rawData == null || rawData.trim().length() <= 0) {
            log.error("登录接口 参数 rawData 为空！");
            return Results.paramError("登录接口 参数 rawData 不能为空！");
        }
        String signature = userAuthVO.getSignature();
        if (signature == null || signature.trim().length() <= 0) {
            log.error("登录接口 参数 signature 为空！");
            return Results.paramError("登录接口 参数 signature 不能为空！");
        }
        String encryptedData = userAuthVO.getEncryptedData();
        if (encryptedData == null || encryptedData.trim().length() <= 0) {
            log.error("登录接口 参数 encryptedData 为空！");
            return Results.paramError("登录接口 参数 encryptedData 不能为空！");
        }
        String iv = userAuthVO.getIv();
        if (iv == null || iv.trim().length() <= 0) {
            log.error("登录接口 参数 iv 为空！");
            return Results.paramError("登录接口 参数 iv 不能为空！");
        }
        String userId = null;
        try {
            String token = request.getHeaders(Token.NAME).nextElement();
            userId = jwtUtil.getUserId(token);
        } catch (Throwable e) {
            log.error(e.getMessage(), e);
        }
        WxMiniUser wxMiniUser = null;
        if (userId == null) {
            log.error("token 错误，无法获取当前登录用户");
            return Results.tokenError("无法从token获取用户id");
        } else {
            log.info("当前登录用户id={}", userId);
            wxMiniUser = getById(userId);
        }

        if (wxMiniUser == null) {
            log.error("登录接口 token 错误！");
            return Results.tokenError("token错误，用户不存在");
        }
        String sessionKey = wxMiniUser.getSessionKey();

        /* 验证签名 */
        String localSignature = Sha1Utils.sha1(rawData + sessionKey);
        if (localSignature.equals(signature)) {
            log.info("签名验证通过！");
        } else {
            log.info("签名验证失败！signature={}  localSignature={}", signature, localSignature);
            return Results.error("用户签名验证失败");
        }

        /* 解密数据 */
        log.info("开始解密  encryptedData={}", encryptedData);
        log.info("开始解密  sessionKey={}", sessionKey);
        log.info("开始解密  iv={}", iv);
        String userData = AesUtils.aesCbcDecode(encryptedData, sessionKey, iv);
        if (userData == null || userData.trim().length() <= 0) {
            return Results.error("数据解密失败");
        }
        log.info("解密后数据 = {}", userData);
        JSONObject userJson = JSON.parseObject(userData);

        JSONObject watermark = userJson.getJSONObject("watermark");
        String watermarkAppid = watermark.getString("appid");
        Long watermarkTimestamp = watermark.getLong("timestamp") * 1000;
        long now = System.currentTimeMillis();
        long abs = Math.abs(now - watermarkTimestamp);
        log.info("time=[{}]", watermarkTimestamp);
        log.info("now=[{}]", now);
        if (!appId.equals(watermarkAppid) || abs > (1000 * 60)) {
            return Results.error("数据水印无效");
        }
        wxMiniUser.setUnionId(userJson.getString("unionId"));
        wxMiniUser.setNickname(userJson.getString("nickName"));
        wxMiniUser.setAvatarUrl(userJson.getString("avatarUrl"));
        wxMiniUser.setGender(userJson.getString("gender"));
        wxMiniUser.setCountry(userJson.getString("country"));
        wxMiniUser.setProvince(userJson.getString("province"));
        wxMiniUser.setCity(userJson.getString("city"));
        wxMiniUser.setLanguage(userJson.getString("language"));
        return Results.success(updateById(wxMiniUser));
    }


}
